'''
info是项目最大的包，存放业务逻辑代码(蓝图、静态文件、模板文件等)
utils包专门存放项目中会使用到的一些工具包
modules包用来存放所有的蓝图模块
static静态资源
'''

from flask import Flask, render_template
from flask import g
from flask_sqlalchemy import SQLAlchemy
from flask_session import Session
import redis
from config import Config  # 导入Config,config_dict类
from config import config_dict
# 集成日志功能
import logging
from logging.handlers import RotatingFileHandler


db = SQLAlchemy()  # 解决models.py文件导入db报错的问题
redis_store = None  # 全局变量

def create_app(env):
    '''flask应用,一些对象,创建app之后的一系列工作'''
    # config_type是字典名,env为键(develop或product)
    config_type = config_dict[env]  # 以什么模式运行
    app = Flask(__name__)

    # 从类对象中加载配置文件,Config为数据库session等的类,config_type是什么模式的类
    app.config.from_object(Config)  # Config和config_type在config.py中
    app.config.from_object(config_type)

    # 创建SQLAlchemy对象
    # 原： db = SQLAlchemy(app)
    # db = SQLAlchemy()  # 创建SQLAlchemy对象
    db.init_app(app)  # 初始化SQLAlchemy对象

    # 创建redis仓库
    global redis_store  # 修改全局变量
    redis_store = redis.StrictRedis(host=Config.REDIS_HOST, port=Config.REDIS_PORT)

    # 读取app中的session信息， 指定存储位置
    Session(app)

    # CSRF 防护
    # flask_wtf扩展提供了一个CSRFProtect(app)方法,从而我们不用自己写@app.before_request钩子函数手动来给每一个POST请求添加CSRF验证
    from flask_wtf import CSRFProtect
    CSRFProtect(app)  # 保护app中的路由路径和视图函数
    from flask_wtf.csrf import generate_csrf
    @app.after_request
    def after_request(response):
        # 生成 csrf_token 随机值
        csrf_token = generate_csrf() # CSRFProtect里自带的随机数方法
        # 将 csrf_token 的值传给前端浏览器（通过设置cookie）
        response.set_cookie("csrf_token", csrf_token)
        return response

    # 添加自定义过滤器
    from info.utils.common import do_index_class
    app.add_template_filter(do_index_class, "to_classname")

    # 调用日志记录函数
    log_file(config_type.LOG_LV)

    # 注册首页蓝图到app中
    from info.modules.index import index_blu  # 解决循环导入问题
    app.register_blueprint(index_blu)
    # 注册passport蓝图(图形验证码)
    from info.modules.passport import passport_blu
    app.register_blueprint(passport_blu)
    # 注册新闻详情页蓝图
    from info.modules.news_detail import news_detail_blu
    app.register_blueprint(news_detail_blu)
    # 注册个人中心页蓝图
    from info.modules.profile import profile_blu
    app.register_blueprint(profile_blu)
    # 注册管理模块蓝图
    from info.modules.admin import admin_blu
    app.register_blueprint(admin_blu)

    # 创建捕获404异常的函数，在某一个视图函数中执行到 abort(404)的时候就会被这个函数捕获
    from info.utils.common import user_login_data
    @app.errorhandler(404)
    @user_login_data
    def page_not_found(_):
        user = g.user
        data = {
            'user': user.to_dict() if user else None
        }
        return render_template('news/404.html', data=data)


    # 返回app到manage.py的调用
    return app


def log_file(LOG_LV):
    """记录日志信息"""
    # 设置哪些日志信息等级要被记录, (优先级：DEBUG < INFO < WARING < ERROR)
    logging.basicConfig(level = LOG_LV)  # 调试debug级
    # 创建日志记录器，指明日志保存的路径、每个日志文件的最大大小、保存的日志文件个数上限
    file_log_handler = RotatingFileHandler("logs/log", maxBytes = 1024 * 1024 * 100, backupCount = 10)
    # 创建日志记录的格式 日志等级 输入日志信息的文件名 行数 日志信息
    formatter = logging.Formatter('%(levelname)s %(filename)s:%(lineno)d %(message)s')
    # 为刚创建的日志记录器设置日志记录格式
    file_log_handler.setFormatter(formatter)
    # 为全局的日志工具对象（flask app使用的）添加日志记录器
    logging.getLogger().addHandler(file_log_handler)
